#include "ThingsBoard.h"
#include <ESP8266WiFi.h>
#include <ModbusMaster.h>
#include <SoftwareSerial.h>

SoftwareSerial DLSerial(5, 4); // (TTL RX, TX) D1,D2 详见文章内引脚图
ModbusMaster node;
uint16_t data[6];
#define WIFI_AP             "ybh_001"
#define WIFI_PASSWORD       "*****"
// See https://thingsboard.io/docs/getting-started-guides/helloworld/
// to understand how to obtain an access token
#define TOKEN          "*********"
#define THINGSBOARD_SERVER  "106.12.252.114"

// Serial driver for ESP
// Initialize the Ethernet client object
WiFiClient espClient;
// Initialize ThingsBoard instance
ThingsBoard tb(espClient);
// the Wifi radio's status
int status = WL_IDLE_STATUS;
bool switch_state = false;
int isled = 0;
int isok = 0;
int resets = 0; //总的udp发送次数
int sensor = 16;  // Digital pin D3  LED

void setup() {
  pinMode(LED_BUILTIN, OUTPUT);
  // initialize serial for debugging
  Serial.begin(9600);
  DLSerial.begin(9600);
  node.begin(1, DLSerial);
  // initialize serial for ESP module
  // initialize ESP module
  WiFi.begin(WIFI_AP, WIFI_PASSWORD);
  InitWiFi();
  pinMode(sensor, OUTPUT);   // LED status
  digitalWrite(sensor, HIGH);
}

// Processes function for RPC call "example_set_temperature"
// RPC_Data is a JSON variant, that can be queried using operator[]
// See https://arduinojson.org/v5/api/jsonvariant/subscript/ for more details
RPC_Response processTemperatureChange(const RPC_Data &data)
{
  Serial.println("Received the set temperature RPC method");

  // Process data

  float example_temperature = data["temp"];

  Serial.print("Example temperature: ");
  Serial.println(example_temperature);

  // Just an response example
  return RPC_Response("example_response", 42);
}

// Processes function for RPC call "example_set_switch"
// RPC_Data is a JSON variant, that can be queried using operator[]
// See https://arduinojson.org/v5/api/jsonvariant/subscript/ for more details
RPC_Response processSwitchChange(const RPC_Data &data)
{
  Serial.println("Received the set switch method");

  // Process data
  
  switch_state = data["switch"];
  
  Serial.print("Example switch state: ");
  Serial.println(switch_state);
  if(switch_state){
    //digitalWrite (Status, HIGH);
    tb.sendTelemetryInt("led", 1);
    digitalWrite(sensor, LOW);
  }else{
    //digitalWrite(sensor,LOW);
    tb.sendTelemetryInt("led", 0);
    digitalWrite(sensor, HIGH);
  }
  // Just an response example
  return RPC_Response("example_response", 22.02);
}

const size_t callbacks_size = 2;
RPC_Callback callbacks[callbacks_size] = {
  { "example_set_temperature",    processTemperatureChange },
  { "open",         processSwitchChange }
};

bool subscribed = false;

void loop() {

  if (WiFi.status() != WL_CONNECTED) {
    // Still connecting
    reconnect();
  }
  if(isled==0){
    digitalWrite(LED_BUILTIN, LOW);  // Turn the LED off by making the voltage HIGH
    isled=1;
  }else{
    digitalWrite(LED_BUILTIN, HIGH);  // Turn the LED off by making the voltage HIGH
    isled=0;
  }
  //Serial.println("333333333333");
  //Serial.println(WiFi.localIP());
  if (!tb.connected()) {
    subscribed = false;
    digitalWrite(LED_BUILTIN, LOW);  // Turn the LED off by making the voltage HIGH

    // Connect to the ThingsBoard
    Serial.print("Connecting to: ");
    Serial.print(THINGSBOARD_SERVER);
    Serial.print(" with token ");
    Serial.println(TOKEN);
    if (!tb.connect(THINGSBOARD_SERVER, TOKEN)) {
      Serial.println("Failed to connect, retrying ...");
      if(isok==0){
        digitalWrite(sensor, LOW);  // Turn the LED off by making the voltage HIGH
        isok=1;
      }else{
        digitalWrite(sensor, HIGH);  // Turn the LED off by making the voltage HIGH
        isok=0;
      }      
      return;
    }
  }

  if(resets>=20){
      modbusInfo();
      tb.sendTelemetryInt("humi", data[0]);
      tb.sendTelemetryInt("temp", data[1]);
      resets = 0;
  }
  resets++;   

  
  if (!subscribed) {
    Serial.println("Subscribing for RPC...");

    // Perform a subscription. All consequent data processing will happen in
    // processTemperatureChange() and processSwitchChange() functions,
    // as denoted by callbacks[] array.
    if (!tb.RPC_Subscribe(callbacks, callbacks_size)) {
      Serial.println("Failed to subscribe for RPC");
      return;
    }

    Serial.println("Subscribe done");
    subscribed = true;
  }


  tb.loop();
  delay(500);
}

void InitWiFi()
{
  Serial.println("Connecting to AP ...");
  // attempt to connect to WiFi network

  WiFi.begin(WIFI_AP, WIFI_PASSWORD);
  //stat_info = wifi_softap_get_station_info();
  
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  Serial.println("Connected to AP");
}

void reconnect() {
  // Loop until we're reconnected
  status = WiFi.status();
  Serial.println(WiFi.localIP());
  if ( status != WL_CONNECTED) {
    WiFi.begin(WIFI_AP, WIFI_PASSWORD);
    while (WiFi.status() != WL_CONNECTED) {
      delay(500);
      Serial.print(".");
    }
    Serial.println("Connected to AP");
  }
}


void modbusInfo(){
  static uint32_t i;
  uint8_t j, result;
  
  i++;
  
  // set word 0 of TX buffer to least-significant word of counter (bits 15..0)
  //node.setTransmitBuffer(0, lowWord(i));
  
  // set word 1 of TX buffer to most-significant word of counter (bits 31..16)
  //node.setTransmitBuffer(1, highWord(i));
  
  // slave: write TX buffer to (2) 16-bit registers starting at register 0
  //result = node.writeMultipleRegisters(0, 2);
  
  // slave: read (6) 16-bit registers starting at register 2 to RX buffer
  result = node.readHoldingRegisters(0, 2);
  
  // do something with data if read is successful
  if (result == node.ku8MBSuccess)
  {
    for (j = 0; j < 6; j++)
    {
      data[j] = node.getResponseBuffer(j);
    }
  }
 
}
